package net.asrsmid.config;

import java.util.List;

import org.dom4j.Document;
import org.dom4j.Element;

/**
 * public class AsRsConfigLoader<br><br>
 * The AsRsConfigLoader class helps to validate and load settings from an XML config file
 * @author Chen WANG
 * @since 09 June 2011
 */
public class AsRsConfigLoader {
	private static final String CONFIG_SCHEMA_FILE = "asrsmid-conf.xsd";
	private static final String REPORT_SCHEMA_FILE = "asrsmid-reports.xsd";
	private static final String DEFAULT_ASAPP_ID = "default_as";
	private static final String DEFAULT_RSAPP_ID = "default_rs";
	
	private static final AsRsAuthMode default_as_auth_mode = AsRsAuthMode.ANONYMOUS;
	private static final String default_as_default_user_name = null;
	private static final String default_as_default_user_password = null;
	private static final String default_as_driver_name = "org.olap4j.driver.xmla.XmlaOlap4jDriver";
	private static final String default_as_server_name = "localhost";
	private static final String default_as_webservice_extension_name = "olap";
	private static final String default_as_isapi_extension_name = "msmdpump.dll";
	private static final String default_as_catalog_name = "AdventureWorksDW2008R2";
	private static final String default_as_cube_name = "Adventure Works";
	private static final int default_as_pool_min_idle = 5;
	private static final int default_as_pool_max_idle = 10;
	private static final int default_as_pool_max_active = 15;
	private static final int default_as_pool_max_wait = 60000;
	
	private static final AsRsAuthMode default_rs_auth_mode = AsRsAuthMode.WINDOWS;
	private static final String default_rs_default_user_name = null;
	private static final String default_rs_default_user_password = null;
	private static final String default_rs_name_space_uri = "http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices";
	private static final String default_rs_local_part = "ReportExecutionService";
	private static final String default_rs_wsdl_uri = "http://localhost/ReportServer/ReportExecution2005.wsdl";
	private static final String default_rs_endpoint_uri = "http://localhost/ReportServer/ReportExecution2005.asmx";
	private static final int default_rs_pool_min_idle = 5;
	private static final int default_rs_pool_max_idle = 10;
	private static final int default_rs_pool_max_active = 15;
	private static final int default_rs_pool_max_wait = 60000;

	/**
	 * Loads the settings from the given config file to an AsRsConfig object
	 * @param configFileName the XML config file name
	 * @return If the config file is valid, an AsRsConfig object containing 
	 * the config settings will be returned. Else an AsRsConfig object with
	 * the default values will be returned
	 */
	public static AsRsConfig loadAsRsConfig(String configFileName) {
		AsRsConfig config = null;
		try {
			String folderPath = configFileName.substring(0, configFileName.lastIndexOf("\\") + 1);
			AsRsConfigValidator validator = new AsRsConfigValidator(configFileName, folderPath + CONFIG_SCHEMA_FILE);
			Document doc = validator.validate();
			
			if (doc == null) {
				System.out.println("Config file '" + configFileName + "' validation error, config data not loaded");
				return loadDefaultAsRsConfigParams();
			}
			
			Element root = doc.getRootElement();
	        
	        // config object
	        config = new AsRsConfig();
	        
	        // msas config part
	        @SuppressWarnings("unchecked")
			List<Element> asAppNodeList = (List<Element>) root.element("as-applications").elements("as-application");
	        for (Element asAppNode : asAppNodeList) {
	        	String appId = asAppNode.element("application-id").getText();
	        	AsApplication asApp = new AsApplication(appId);
	        	config.putAsApplication(asApp);

	        	Element httpSecurityNode = asAppNode.element("http-security");
	        	if (httpSecurityNode == null) {
	        		// if http-security node not found
	        		asApp.setAuthMode(default_as_auth_mode);
		    		asApp.setDefaultUserName(default_as_default_user_name);
		    		asApp.setDefaultUserPassword(default_as_default_user_password);
	        	} else {
	        		// auth-mode node
	        		Element authModeNode = httpSecurityNode.element("auth-mode");
	        		if (authModeNode == null || authModeNode.getText() == null) {
	        			// if auth-mode node not found
	        			asApp.setAuthMode(default_as_auth_mode);
	        		} else {
	        			try {
	        				AsRsAuthMode authMode = AsRsAuthMode.ANONYMOUS;
	        				int configValue = Integer.parseInt(authModeNode.getText());
	        				if (configValue == 1) {
	        					authMode = AsRsAuthMode.WINDOWS;
	        				} else if (configValue == 2) {
	        					authMode = AsRsAuthMode.BASIC;
	        				} else if (configValue == 3) {
	        					authMode = AsRsAuthMode.CUSTOMIZED;
	        				}
	        				asApp.setAuthMode(authMode);
	        			} catch (Exception e) {
	        				asApp.setAuthMode(default_as_auth_mode);
	        			}
	        		}
	        		
	        		// default-user-name node
	        		Element defaultUserNameNode = httpSecurityNode.element("default-user-name");
	        		if (defaultUserNameNode == null || defaultUserNameNode.getText() == null) {
	        			// if auth-mode node not found
	        			asApp.setDefaultUserName(default_as_default_user_name);
	        		} else {
	        			asApp.setDefaultUserName(defaultUserNameNode.getText());
	        		}
	        		
	        		// default-user-password node
	        		Element defaultUserPasswordNode = httpSecurityNode.element("default-user-password");
	        		if (defaultUserPasswordNode == null || defaultUserPasswordNode.getText() == null) {
	        			// if auth-mode node not found
	        			asApp.setDefaultUserPassword(default_as_default_user_password);
	        		} else {
	        			asApp.setDefaultUserPassword(defaultUserPasswordNode.getText());
	        		}
	        	}
	        	
	        	// olap4j-connectivity node
	        	Element olap4jConectivityNode = asAppNode.element("olap4j-connectivity");
	        	if (olap4jConectivityNode == null) {
	        		// if olap4j-connectivity node not found
	        		asApp.setDriverName(default_as_driver_name);
	        		asApp.setServerName(default_as_server_name);
		    		asApp.setWebserviceExtensionName(default_as_webservice_extension_name);
		    		asApp.setIsapiExtensionName(default_as_isapi_extension_name);
		    		asApp.setCatalogName(default_as_catalog_name);
		    		asApp.setCubeName(default_as_cube_name);
	        	} else {
	        		// driver-name node
	        		Element driverNameNode = olap4jConectivityNode.element("driver-name");
	        		if (driverNameNode == null || driverNameNode.getText() == null) {
	        			// if driver-name node not found
	        			asApp.setDriverName(default_as_driver_name);
	        		} else {
	        			asApp.setDriverName(driverNameNode.getText());
	        		}
	        		
	        		// server-name node
	        		Element serverNameNode = olap4jConectivityNode.element("server-name");
	        		if (serverNameNode == null || serverNameNode.getText() == null) {
	        			// if server-name node not found
	        			asApp.setServerName(default_as_server_name);
	        		} else {
	        			asApp.setServerName(serverNameNode.getText());
	        		}
	        		
	        		// webservice-extension-name node
	        		Element webserviceExtensionNameNode = olap4jConectivityNode.element("webservice-extension-name");
	        		if (webserviceExtensionNameNode == null || webserviceExtensionNameNode.getText() == null) {
	        			// if webservice-extension-name node not found
	        			asApp.setWebserviceExtensionName(default_as_webservice_extension_name);
	        		} else {
	        			asApp.setWebserviceExtensionName(webserviceExtensionNameNode.getText());
	        		}
	        		
	        		// isapi-extension-name node
	        		Element isapiExtensionNameNode = olap4jConectivityNode.element("isapi-extension-name");
	        		if (isapiExtensionNameNode == null || isapiExtensionNameNode.getText() == null) {
	        			// if isapi-extension-name node not found
	        			asApp.setIsapiExtensionName(default_as_isapi_extension_name);
	        		} else {
	        			asApp.setIsapiExtensionName(isapiExtensionNameNode.getText());
	        		}
	        		
	        		// catalog-name node
	        		Element catalogNameNode = olap4jConectivityNode.element("catalog-name");
	        		if (catalogNameNode == null || catalogNameNode.getText() == null) {
	        			// if catalog-name node not found
	        			asApp.setCatalogName(default_as_catalog_name);
	        		} else {
	        			asApp.setCatalogName(catalogNameNode.getText());
	        		}
	        		
	        		// cube-name node
	        		Element cubeNameNode = olap4jConectivityNode.element("cube-name");
	        		if (cubeNameNode == null || cubeNameNode.getText() == null) {
	        			// if cube-name node not found
	        			asApp.setCubeName(default_as_cube_name);
	        		} else {
	        			asApp.setCubeName(cubeNameNode.getText());
	        		}
	        	}
	        	
	        	// connection-pool node
	        	Element connectionPoolNode = asAppNode.element("connection-pool");
	        	if (connectionPoolNode == null) {
	        		// if connection-pool node not founds
	        		asApp.setPoolMinIdle(default_as_pool_min_idle);
		    		asApp.setPoolMaxIdle(default_as_pool_max_idle);
		    		asApp.setPoolMaxActive(default_as_pool_max_active);
		    		asApp.setPoolMaxWait(default_as_pool_max_wait);
	        	} else {
	        		// pool-min-idle node
	        		Element poolMinIdleNode = connectionPoolNode.element("pool-min-idle");
	        		if (poolMinIdleNode == null || poolMinIdleNode.getText() == null) {
	        			// if pool-min-idle node not found
	        			asApp.setPoolMinIdle(default_as_pool_min_idle);
	        		} else {
	        			try {
	        				int configValue = Integer.parseInt(poolMinIdleNode.getText());
	        				asApp.setPoolMinIdle(configValue);
	        			} catch (Exception e) {
	        				asApp.setPoolMinIdle(default_as_pool_min_idle);
	        			}
	        		}
	        		
	        		// pool-max-idle node
	        		Element poolMaxIdleNode = connectionPoolNode.element("pool-max-idle");
	        		if (poolMaxIdleNode == null || poolMaxIdleNode.getText() == null) {
	        			// if pool-max-idle node not found
	        			asApp.setPoolMaxIdle(default_as_pool_max_idle);
	        		} else {
	        			try {
	        				int configValue = Integer.parseInt(poolMaxIdleNode.getText());
	        				asApp.setPoolMaxIdle(configValue);
	        			} catch (Exception e) {
	        				asApp.setPoolMaxIdle(default_as_pool_max_idle);
	        			}
	        		}
	        		
	        		// pool-max-active node
	        		Element poolMaxActiveNode = connectionPoolNode.element("pool-max-active");
	        		if (poolMaxActiveNode == null || poolMaxActiveNode.getText() == null) {
	        			// if pool-max-active node not found
	        			asApp.setPoolMaxActive(default_as_pool_max_active);
	        		} else {
	        			try {
	        				int configValue = Integer.parseInt(poolMaxActiveNode.getText());
	        				asApp.setPoolMaxActive(configValue);
	        			} catch (Exception e) {
	        				asApp.setPoolMaxActive(default_as_pool_max_active);
	        			}
	        		}
	        		
	        		// pool-max-wait node
	        		Element poolMaxWaitNode = connectionPoolNode.element("pool-max-wait");
	        		if (poolMaxWaitNode == null || poolMaxWaitNode.getText() == null) {
	        			// if pool-max-wait node not found
	        			asApp.setPoolMaxWait(default_as_pool_max_wait);
	        		} else {
	        			try {
	        				int configValue = Integer.parseInt(poolMaxWaitNode.getText());
	        				asApp.setPoolMaxWait(configValue);
	        			} catch (Exception e) {
	        				asApp.setPoolMaxWait(default_as_pool_max_wait);
	        			}
	        		}
	        	}
	        }
	        
	        // msrs config part
	        Element rsAppsNode = root.element("rs-applications");
			@SuppressWarnings("unchecked")
			List<Element> rsAppNodeList = (List<Element>) rsAppsNode.elements("rs-application");;
	        for (Element rsAppNode : rsAppNodeList) {
	        	String appId = rsAppNode.element("application-id").getText();
	        	RsApplication rsApp = new RsApplication(appId);
	        	config.putRsApplication(rsApp);
	        	
	        	// http-security node
	        	Element httpSecurityNode = rsAppNode.element("http-security");
	        	if (httpSecurityNode == null) {
	        		// if http-security node not found
	        		rsApp.setAuthMode(default_rs_auth_mode);
		    		rsApp.setDefaultUserName(default_rs_default_user_name);
		    		rsApp.setDefaultUserPassword(default_rs_default_user_password);
	        	} else {
	        		// auth-mode node
	        		Element authModeNode = httpSecurityNode.element("auth-mode");
	        		if (authModeNode == null || authModeNode.getText() == null) {
	        			// if auth-mode node not found
	        			rsApp.setAuthMode(default_rs_auth_mode);
	        		} else {
	        			try {
	        				AsRsAuthMode authMode = AsRsAuthMode.ANONYMOUS;
	        				int configValue = Integer.parseInt(authModeNode.getText());
	        				if (configValue == 1) {
	        					authMode = AsRsAuthMode.WINDOWS;
	        				} else if (configValue == 2) {
	        					authMode = AsRsAuthMode.BASIC;
	        				} else if (configValue == 3) {
	        					authMode = AsRsAuthMode.CUSTOMIZED;
	        				}
	        				rsApp.setAuthMode(authMode);
	        			} catch (Exception e) {
	        				rsApp.setAuthMode(default_rs_auth_mode);
	        			}
	        		}
	        		
	        		// default-user-name node
	        		Element defaultUserNameNode = httpSecurityNode.element("default-user-name");
	        		if (defaultUserNameNode == null || defaultUserNameNode.getText() == null) {
	        			// if auth-mode node not found
	        			rsApp.setDefaultUserName(default_rs_default_user_name);
	        		} else {
	        			rsApp.setDefaultUserName(defaultUserNameNode.getText());
	        		}
	        		
	        		// default-user-password node
	        		Element defaultUserPasswordNode = httpSecurityNode.element("default-user-password");
	        		if (defaultUserPasswordNode == null || defaultUserPasswordNode.getText() == null) {
	        			// if auth-mode node not found
	        			rsApp.setDefaultUserPassword(default_rs_default_user_password);
	        		} else {
	        			rsApp.setDefaultUserPassword(defaultUserPasswordNode.getText());
	        		}
	        	}
	        	
	        	// webservice-connectivity node
	        	Element webserviceConectivityNode = rsAppNode.element("webservice-connectivity");
	        	if (webserviceConectivityNode == null) {
	        		// if webservice-connectivity node not found
		    		rsApp.setNameSpaceUri(default_rs_name_space_uri);
		    		rsApp.setLocalPart(default_rs_local_part);
		    		rsApp.setWsdlUri(default_rs_wsdl_uri);
		    		rsApp.setEndpointUri(default_rs_endpoint_uri);
	        	} else {	        		
	        		// namespace-uri node
	        		Element nameSpaceUriNode = webserviceConectivityNode.element("namespace-uri");
	        		if (nameSpaceUriNode == null || nameSpaceUriNode.getText() == null) {
	        			// if namespace-uri node not found
	        			rsApp.setNameSpaceUri(default_rs_name_space_uri);
	        		} else {
	        			rsApp.setNameSpaceUri(nameSpaceUriNode.getText());
	        		}
	        		
	        		// local-part node
	        		Element localPartNode = webserviceConectivityNode.element("local-part");
	        		if (localPartNode == null || localPartNode.getText() == null) {
	        			// if local-part node not found
	        			rsApp.setLocalPart(default_rs_local_part);
	        		} else {
	        			rsApp.setLocalPart(localPartNode.getText());
	        		}
	        		
	        		// wsdl-uri node
	        		Element wsdlUriNode = webserviceConectivityNode.element("wsdl-uri");
	        		if (wsdlUriNode == null || wsdlUriNode.getText() == null) {
	        			// if wsdl-uri node not found
	        			rsApp.setWsdlUri(default_rs_wsdl_uri);
	        		} else {
	        			rsApp.setWsdlUri(wsdlUriNode.getText());
	        		}
	        		
	        		// endpoint-uri node
	        		Element endpointUriNode = webserviceConectivityNode.element("endpoint-uri");
	        		if (endpointUriNode == null || endpointUriNode.getText() == null) {
	        			// if endpoint-uri node not found
	        			rsApp.setEndpointUri(default_rs_endpoint_uri);
	        		} else {
	        			rsApp.setEndpointUri(endpointUriNode.getText());
	        		}
	        	}
	        	
	        	// proxy-pool node
	        	Element proxyPoolNode = rsAppNode.element("proxy-pool");
	        	if (proxyPoolNode == null) {
	        		// if proxy-pool node not found
	        		rsApp.setPoolMinIdle(default_rs_pool_min_idle);
		    		rsApp.setPoolMaxIdle(default_rs_pool_max_idle);
		    		rsApp.setPoolMaxActive(default_rs_pool_max_active);
		    		rsApp.setPoolMaxWait(default_rs_pool_max_wait);
	        	} else {
	        		// pool-min-idle node
	        		Element poolMinIdleNode = proxyPoolNode.element("pool-min-idle");
	        		if (poolMinIdleNode == null || poolMinIdleNode.getText() == null) {
	        			// if pool-min-idle node not found
	        			rsApp.setPoolMinIdle(default_rs_pool_min_idle);
	        		} else {
	        			try {
	        				int configValue = Integer.parseInt(poolMinIdleNode.getText());
	        				rsApp.setPoolMinIdle(configValue);
	        			} catch (Exception e) {
	        				rsApp.setPoolMinIdle(default_rs_pool_min_idle);
	        			}
	        		}
	        		
	        		// pool-max-idle node
	        		Element poolMaxIdleNode = proxyPoolNode.element("pool-max-idle");
	        		if (poolMaxIdleNode == null || poolMaxIdleNode.getText() == null) {
	        			// if pool-max-idle node not found
	        			rsApp.setPoolMaxIdle(default_rs_pool_max_idle);
	        		} else {
	        			try {
	        				int configValue = Integer.parseInt(poolMaxIdleNode.getText());
	        				rsApp.setPoolMaxIdle(configValue);
	        			} catch (Exception e) {
	        				rsApp.setPoolMaxIdle(default_rs_pool_max_idle);
	        			}
	        		}
	        		
	        		// pool-max-active node
	        		Element poolMaxActiveNode = proxyPoolNode.element("pool-max-active");
	        		if (poolMaxActiveNode == null || poolMaxActiveNode.getText() == null) {
	        			// if pool-max-active node not found
	        			rsApp.setPoolMaxActive(default_rs_pool_max_active);
	        		} else {
	        			try {
	        				int configValue = Integer.parseInt(poolMaxActiveNode.getText());
	        				rsApp.setPoolMaxActive(configValue);
	        			} catch (Exception e) {
	        				rsApp.setPoolMaxActive(default_rs_pool_max_active);
	        			}
	        		}
	        		
	        		// pool-max-wait node
	        		Element poolMaxWaitNode = proxyPoolNode.element("pool-max-wait");
	        		if (poolMaxWaitNode == null || poolMaxWaitNode.getText() == null) {
	        			// if pool-max-wait node not found
	        			rsApp.setPoolMaxWait(default_rs_pool_max_wait);
	        		} else {
	        			try {
	        				int configValue = Integer.parseInt(poolMaxWaitNode.getText());
	        				rsApp.setPoolMaxWait(configValue);
	        			} catch (Exception e) {
	        				rsApp.setPoolMaxWait(default_rs_pool_max_wait);
	        			}
	        		}
	        	}
	        	
	        	// report-files node
	        	Element reportFileListNode = rsAppsNode.element("report-files");
	        	if (reportFileListNode != null) {
	        		// all report-file node
	        		@SuppressWarnings("unchecked")
					List<Element> reportFileNodeList = (List<Element>) reportFileListNode.elements("report-file");
	        		for (Element reportFileNode : reportFileNodeList) {
	        			// save file path
	        			String reportFilePath = folderPath + reportFileNode.getText();
	        			
	        			// load reports
	        			AsRsConfigValidator reportsValidator = new AsRsConfigValidator(reportFilePath, folderPath + REPORT_SCHEMA_FILE);
	        			Document d = reportsValidator.validate();
	        			
	        			if (d != null) {
		        	        @SuppressWarnings("unchecked")
							List<Element> reportNodeList = (List<Element>) (d.getRootElement()).elements("report");
		        	        for (Element reportNode : reportNodeList) {
		        	        	String reportAppId = reportNode.element("application-id").getText();
		        	        	String reportName = reportNode.element("name").getText();
		        	        	String reportServerPath = reportNode.element("server-path").getText();
		        	        	String reportDescription = null;
		        	        	Element descriptionNode = reportNode.element("description");
		        	        	if (descriptionNode != null)
		        	        		reportDescription = descriptionNode.getText();

		        	        	config.putReport(new RsReport(reportAppId, reportName, reportServerPath, reportDescription));
		        	        }
	        			}
	        		}
	        	}
	        }
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return config;
	}
	
	private static AsRsConfig loadDefaultAsRsConfigParams() {
		AsRsConfig config = new AsRsConfig();
		AsApplication asApp = new AsApplication(DEFAULT_ASAPP_ID);
		RsApplication rsApp = new RsApplication(DEFAULT_RSAPP_ID);
		config.putAsApplication(asApp);
		config.putRsApplication(rsApp);
		
		// default as application
		asApp.setAuthMode(default_as_auth_mode);
		asApp.setDefaultUserName(default_as_default_user_name);
		asApp.setDefaultUserPassword(default_as_default_user_password);
		asApp.setDriverName(default_as_driver_name);
		asApp.setServerName(default_as_server_name);
		asApp.setWebserviceExtensionName(default_as_webservice_extension_name);
		asApp.setIsapiExtensionName(default_as_isapi_extension_name);
		asApp.setCatalogName(default_as_catalog_name);
		asApp.setCubeName(default_as_cube_name);
		asApp.setPoolMinIdle(default_as_pool_min_idle);
		asApp.setPoolMaxIdle(default_as_pool_max_idle);
		asApp.setPoolMaxActive(default_as_pool_max_active);
		asApp.setPoolMaxWait(default_as_pool_max_wait);
		
		
		// default rs application
		rsApp.setAuthMode(default_rs_auth_mode);
		rsApp.setDefaultUserName(default_rs_default_user_name);
		rsApp.setDefaultUserPassword(default_rs_default_user_password);
		rsApp.setNameSpaceUri(default_rs_name_space_uri);
		rsApp.setLocalPart(default_rs_local_part);
		rsApp.setWsdlUri(default_rs_wsdl_uri);
		rsApp.setEndpointUri(default_rs_endpoint_uri);
		rsApp.setPoolMinIdle(default_rs_pool_min_idle);
		rsApp.setPoolMaxIdle(default_rs_pool_max_idle);
		rsApp.setPoolMaxActive(default_rs_pool_max_active);
		rsApp.setPoolMaxWait(default_rs_pool_max_wait);
		
		return config;
	}
}